package com.winit.project.manager;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.winit.common.base.beans.FileBaseInfo;
import com.winit.common.base.beans.LoginUser;
import com.winit.common.util.*;
import com.winit.deploy.service.DeployService;
import com.winit.project.core.bean.EditionInfo;
import com.winit.project.core.bean.PackageTypeEnum;
import com.winit.project.core.bean.ProjectInfo;
import com.winit.project.core.branch.Branch;
import com.winit.project.core.branch.Project;
import com.winit.project.core.branch.ProjectConfig;
import com.winit.project.core.branch.ProjectStatus;
import com.winit.project.core.code.ProjectCode;
import com.winit.project.core.edition.PackageEdition;
import com.winit.project.core.edition.PackageEditionConfig;
import com.winit.project.core.set.ProjectSet;
import com.winit.project.core.set.ProjectSetConfig;
import com.winit.project.task.BuildStatusEnum;
import com.winit.project.task.BuildTask;
import com.winit.project.task.BuildTaskContainer;
import com.winit.project.util.ProjectUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.util.*;

/**
 * Created by wangjian on 16/9/7.
 */
@Component
public class ProjectManager {

    private static final Logger logger = LoggerFactory.getLogger(ProjectManager.class);

    @Autowired
    private DeployService deployService;

    /**
     * 查询工程列表
     *
     * @param typeEnum  工程类型
     * @param onlyTrunk 是否只显示主干工程
     * @param isShowJar 是否显示jar工程
     * @return
     */
    public List<ProjectInfo> getProjectList(PackageTypeEnum typeEnum, boolean onlyTrunk, boolean isShowJar) throws Exception {
        logger.info("查询工程列表,typeEnum=" + typeEnum.getDesc() + ",onlyTrunk=" + onlyTrunk + ",isShowJar=" + isShowJar);
        File projectFile = new File(ProjectUtil.PROJECT_DIR);
        if (!projectFile.exists()) {
            logger.error("查询工程列表,工程根目录不存在,请联系beetle管理员!path=" + ProjectUtil.PROJECT_DIR);
            throw new Exception("查询工程列表,工程根目录不存在,请联系beetle管理员!path=" + ProjectUtil.PROJECT_DIR);
        }
        List<ProjectInfo> list = new ArrayList<>();
        for (File f : projectFile.listFiles()) {
            if (!f.isDirectory()) {
                continue;
            }
            ProjectSet projectSet = new ProjectSet(f.getName(), true);
            if (!PackageTypeEnum.ALL.equals(typeEnum)
                    && !projectSet.getProjectSetConfig().getPackageType().equals(typeEnum.getDesc())) {
                continue;
            }
            if (!isShowJar && projectSet.getProjectSetConfig().getPackageType().equals(PackageTypeEnum.MAVEN_JAR.getDesc())) {
                continue;
            }

            if (onlyTrunk) {
                list.add(((Project) projectSet.getProject(f.getName())).projectInfo);
                continue;
            }
            List<Branch> branches = projectSet.listBranches(true);
            if (branches.size() > 0) {
                for (int i = 0; i < branches.size(); i++) {
                    Project project = (Project) branches.get(i);
                    list.add(project.projectInfo);
                }
            }
        }
        Collections.sort(list);
        return list;
    }

    /**
     * 获取主干下工程列表
     *
     * @param trunkName 主干工程名
     * @return
     * @throws Exception
     */
    public List<ProjectInfo> getProjectListByTrunkName(String trunkName) throws Exception {
        logger.info("获取主干下工程列表,trunkName=" + trunkName);
        BAssert.isEmpty("获取主干下工程列表,主干名为空", logger, trunkName);
        ProjectSet projectSet = new ProjectSet(trunkName, true);

        List<ProjectInfo> list = new ArrayList<>();
        List<Branch> branches = projectSet.listBranches(true);
        for (int i = 0; i < branches.size(); i++) {
            Project project = (Project) branches.get(i);
            list.add(project.projectInfo);
        }
        Collections.sort(list);
        return list;
    }

    public boolean isProjectExist(String projectName) {
        try {
            Project project = new Project(projectName, true);
            return project.isProjectExist();
        } catch (Exception e) {
            logger.warn("com.winit.project.manager.ProjectManager.isProjectExist 异常", e);
            return false;
        }
    }

    public boolean isEditionExist(String projectName, String editionNum) throws Exception {
        Project project = new Project(projectName, true);
        return project.isEditionExist(editionNum);
    }

    public ProjectInfo getProjectInfo(String projectName) throws Exception {
        Project project = new Project(projectName, true);
        return project.projectInfo;
    }

    public boolean delProject(String projectName) throws Exception {
        ProjectSet projectSet = new ProjectSet(projectName, true);
        return projectSet.delProject(projectName);
    }

    public boolean saveProjectInfo(ProjectInfo projectInfo) throws Exception {
        logger.info("保存工程信息,projectInfo=" + ObjectToString.getString(projectInfo));
        String projectName = projectInfo.getProjectName();
        Project project = new Project(projectName, true);
        if (project.isTrunk()) {
            ProjectSetConfig setConfig = new ProjectSetConfig(projectName, true);
            BeanUtils.copyProperties(projectInfo, setConfig);
            setConfig.saveToFile();
        }

        ProjectConfig projectConfig = new ProjectConfig(projectName, true);
        BeanUtils.copyProperties(projectInfo, projectConfig);
        projectConfig.saveToFile();
        return true;
    }

    /**
     * 创建新版本
     *
     * @param projectName
     * @return 返回新版本号
     * @throws Exception
     */
    public String createNewEdition(String projectName, LoginUser userInfo) throws Exception {
        LogUtil.operateLog(userInfo, projectName, ProjectUtil.BUILD_DIR, "", LogUtil.OperateType.CREATE_NEW_EDITION);
        Project project = new Project(projectName, true);
        String editionNum = project.createNewEdition();
        LogUtil.operateLog(userInfo, projectName, editionNum, "", LogUtil.OperateType.CREATE_NEW_EDITION_SUCCESS);
        return editionNum;
    }

    /**
     * 获取工程版本列表
     *
     * @param projectName
     * @param isShowAllE  是否显示所有版本,false时 只显示提交测试版本
     * @return
     * @throws Exception
     */
    public List<EditionInfo> getProjectEditionList(String projectName, boolean isShowAllE) throws Exception {
        return getProjectEditionList(projectName, isShowAllE, true);
    }

    public List<EditionInfo> getProjectEditionList(String projectName, boolean isShowAllE, boolean hasDefault) throws Exception {
        List<EditionInfo> list = new ArrayList<>();
        Project project = new Project(projectName, true);
        ProjectStatus projectStatus = project.getProjectStatus();
        List<PackageEdition> temp = project.listEditions(true, hasDefault);

        JSONObject pass = deployService.getPassProjectAndEdition(projectName);
        String passProject = pass.getString("projectName");
        String passEdition = pass.getString("editionNum");

        String buildStatus = project.getProjectStatus().getBuildStatus();
        BuildStatusEnum statusEnum = Enum.valueOf(BuildStatusEnum.class, buildStatus.toUpperCase());
        for (PackageEdition edition : temp) {
            if (!isShowAllE && !edition.getEditionNum().equals(projectStatus.getQaTestEdition())) {
                continue;
            }
            PackageEditionConfig editionConfig = edition.getPackageEditionConfig();

            EditionInfo info = new EditionInfo();
            BeanUtils.copyProperties(editionConfig, info);
            if (edition.getEditionNum().equals(projectStatus.getQaTestEdition())) {
                info.setShowNum(edition.getEditionNum() + "(测)");
                info.setToTest(true);
            } else if (ProjectUtil.BUILD_DIR.equals(edition.getEditionNum())) {
                switch (statusEnum) {
                    case NEVER_BUILD:
                        info.setShowNum("临时版本(未构建)");
                        break;
                    case ON_BUILD:
                        info.setShowNum("临时版本(构建中)");
                        break;
                    case BUILD_FAILED:
                        info.setShowNum("临时版本(构建失败)");
                        break;
                    case BUILD_SUCCESS:
                        info.setShowNum("临时版本(构建成功)");
                        break;
                    case CREATE_EDITION:
                        info.setShowNum("临时版本(已生成版本)");
                        break;
                    case IN_QUEUE:
                        info.setShowNum("临时版本(构建排队中)");
                        break;
                }
            } else {
                info.setShowNum(edition.getEditionNum());
            }
            if (!StringUtils.isEmpty(passProject) && !StringUtils.isEmpty(passEdition)
                    && passProject.equals(projectName) && passEdition.equals(edition.getEditionNum())) {
                info.setTestStatus(true);
            }
            list.add(info);
        }
        return list;
    }

    /**
     * 编辑工程信息
     *
     * @param info
     * @return
     */
    public boolean editProject(ProjectInfo info) throws Exception {
        String projectName = info.getProjectName();
        logger.info("编辑工程信息,projectInfo=" + ObjectToString.getString(info));
        boolean flag = false;
        Project project = new Project(projectName, false);
        if (project.isProjectExist()) {
            //工程存在时,直接保存信息
            flag = this.saveProjectInfo(info);
        } else {
            //工程不存在,新建工程
            ProjectSet projectSet = new ProjectSet(projectName, false);
            ProjectConfig projectConfig = new ProjectConfig(projectName, false);
            BeanUtils.copyProperties(info, projectConfig);
            if (project.isTrunk()) {
                ProjectSetConfig projectSetConfig = new ProjectSetConfig(projectName, false);
                BeanUtils.copyProperties(info, projectSetConfig);
                flag = projectSet.createBranch(projectSetConfig, projectConfig);
            } else {
                flag = projectSet.createBranch(projectConfig);
            }
        }

        if (flag) {
            //新增jar主干工程时,修改jar-project-list.json
            if (project.isTrunk() && PackageTypeEnum.MAVEN_JAR.getDesc().equals(info.getPackageType())) {
                JSONArray jsonArray = getJarProjectNameList();
                if (!jsonArray.contains(info.getProjectName())) {
                    jsonArray.add(info.getProjectName());
                    JSONFileUtil.saveFileJson(ProjectUtil.PROJECT_DIR + "jar-project-list.json", jsonArray);
                }
            }
            //新增主干工程  调用plan判断svn地址
            try {
                if (project.isTrunk()) {
                    JSONObject json = new JSONObject();
                    json.put("trunk_name", projectName);
                    json.put("svn_url", info.getVcsPath());
                    HttpClientUtil.doPostForJson(Constants.BEETLE_PLAN_URL + "/project/handleProjectSvn", json.toString());
                }
            } catch (Exception e) {
                logger.error("com.winit.project.manager.ProjectManager.editProject 新建主干，调用plan异常 ", e);
            }
            //编辑工程信息时,删除工程原代码 重新下载新代码
            project = new Project(projectName, true);
            ProjectCode projectCode = project.getProjectCode();
            projectCode.removeOldAndCheckNew();
        } else {
            return false;
        }
        return true;
    }

    /**
     * 为项目创建工程
     *
     * @param trunkName
     * @param projectName
     * @param vcsPath
     * @return
     * @throws Exception
     */
    public boolean addProjectForPlan(String trunkName, String projectName, String vcsPath, String dependency) throws Exception {
        if (!projectName.startsWith(trunkName + "_")) {
            throw new Exception("主干工程与分支工程不匹配");
        }
        Project trunk = new Project(trunkName, true);
        if (!trunk.isProjectExist()) {
            throw new Exception("主干工程不存在");
        }

        Project project = new Project(projectName, false);
        if (project.isProjectExist()) {
            throw new Exception("分支工程已存在，不能创建");
        }

        JSONArray jsonArray = JSONArray.parseArray(dependency);
        ProjectSet projectSet = new ProjectSet(projectName, false);
        ProjectConfig projectConfig = new ProjectConfig(projectName, false);
        projectConfig.setConfigPath(trunk.getProjectConfig().getConfigPath());
        projectConfig.setVcsPath(vcsPath);
        projectConfig.setUseSonar(false);

        if ("maven_war".equals(trunk.getProjectSetConfig().getPackageType()) && jsonArray.size() > 0) {
            List<JSONObject> list = new ArrayList<>();
            for (int i = 0; i < jsonArray.size(); i++) {
                list.add(jsonArray.getJSONObject(i));
            }
            projectConfig.setDependency(list);
        }

        return projectSet.createBranch(projectConfig);
    }


    private JSONArray getJarProjectNameList() {
        StringBuffer path = new StringBuffer();
        path.append(ProjectUtil.PROJECT_DIR).append("jar-project-list.json");
        String jars = JSONFileUtil.getFileString(path.toString());
        JSONArray jsonArray = JSONArray.parseArray(jars);
        return jsonArray;
    }

    /**
     * 获取工程文档信息列表
     *
     * @param projectName 工程名
     * @param type        文档类型  sql excel
     * @return {"fileName":"001_sms_ddl.sql","createDate":"2016-09-13 17:15:57","desc":"aaaaaaa"}
     * @throws Exception
     */
    public List<FileBaseInfo> projectFileList(String projectName, String type) throws Exception {
        Project project = new Project(projectName, true);
        if (!project.isProjectExist()) {
            logger.error("获取工程文档信息列表,工程不存在.projectName=" + projectName);
            throw new Exception("获取工程文档信息列表,工程不存在.projectName=" + projectName);
        }
        //存放文件目录
        String fileDir = ProjectUtil.getProjectFileDir(projectName, type);
        List<FileBaseInfo> list = FileUpload.getFileInfoList(fileDir, FileBaseInfo.class);
        return list;
    }

    /**
     * 上传工程相关的sql和excel文件
     *
     * @param projectName
     * @param type
     * @param source
     * @return
     * @throws Exception
     */
    public boolean uploadProjectFile(String projectName, String type, MultipartFile source, LoginUser userInfo) throws Exception {
        Project project = new Project(projectName, true);
        if (!project.isProjectExist()) {
            logger.error("上传工程相关的文件,工程不存在.projectName=" + projectName);
            throw new Exception("上传工程相关的文件,工程不存在.projectName=" + projectName);
        }

        //存放文件目录
        String fileDir = ProjectUtil.getProjectFileDir(projectName, type);
        FileUpload.uploadFile(fileDir, source, new FileBaseInfo(), userInfo, true, true, true);
        return true;
    }

    /**
     * 版本提交测试
     *
     * @param projectName
     * @param editionNum
     * @param type        类型  true 提测  false 取消提测
     * @return
     * @throws Exception
     */
    public boolean editionToTest(String projectName, String editionNum, boolean type, LoginUser userInfo) throws Exception {
        logger.info("com.winit.Project.manager.NewProjectManager.editionToTest. projectName=" + projectName + ",editionNum=" + editionNum + ",type=" + type);
        ProjectStatus status = new ProjectStatus(projectName, true);
        if (type) {
            LogUtil.operateLog(userInfo, projectName, editionNum, "", LogUtil.OperateType.SUBMIT_TO_TEST);
            status.setQaTestEdition(editionNum);
        } else {
            LogUtil.operateLog(userInfo, projectName, editionNum, "", LogUtil.OperateType.SUBMIT_NOT_TO_TEST);
            status.setQaTestEdition("");
        }
        boolean flag = status.saveToFile();
        logger.info("com.winit.Project.manager.NewProjectManager.editionToTest. projectName=" + projectName + ",editionNum=" + editionNum + ",type=" + type + ",返回:" + flag);
        if (flag && type) {
            //保存成功 且 为提交测试
            PackageEdition edition = new PackageEdition(projectName, editionNum, true);
            PackageEditionConfig editionConfig = edition.getPackageEditionConfig();
            ProjectSetConfig setConfig = new ProjectSetConfig(projectName, true);
            ProjectUtil.scpMvnEdition(Enum.valueOf(PackageTypeEnum.class, setConfig.getPackageType().toUpperCase())
                    , projectName, editionNum);
            //提交测试时,初始化版本测试不通过状态
            editionConfig.setNotTestPass(false);
            editionConfig.saveToFile();
        }
        return flag;
    }

    /**
     * 执行构建
     *
     * @param projectName
     * @throws Exception
     */
    public boolean doBuild(String projectName, LoginUser userInfo) throws Exception {
        Project project = new Project(projectName, true);
        BuildTask buildTask = new BuildTask(project, "");
        this.doBuild(buildTask, userInfo);
        return true;
    }

    public boolean doBuild(BuildTask buildTask, LoginUser userInfo) throws Exception {
        LogUtil.operateLog(userInfo, buildTask.getProjectName(), ProjectUtil.BUILD_DIR, "", LogUtil.OperateType.BUILD);
        BuildTaskContainer buildTaskContainer = BuildTaskContainer.getInstance();
        buildTaskContainer.addBuildTask(buildTask);
        return true;
    }
}
